#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <netdb.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/ioctl.h>

#include "client.hpp"

#define PORT	12345
#define HOST	"127.0.0.1"
#define NAME	"ftserver"
#define ERR	" [ERROR] "
#define DBG	" [DEBUG] "
#define MAXCONN	10

void			perror(const char* str)
{
  std::cout << NAME << ERR << str << " : " << strerror(errno) << "\n";
}

void			pdbg(const char* str)
{
  std::cout << NAME << DBG << str << "\n";
}

int			main(int argc, char *argv[])
{
  int			sockfd;
  int			newsockfd;
  int			port;
  int			on = 1;
  socklen_t		socklen;
  char			buf[500];
  struct sockaddr_in	saddr;
  struct sockaddr_in	caddr;
  struct hostent*	listenaddr;
  fd_set		fdset;
  struct timeval	timeout;
  Client		clis[MAXCONN];

  if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    {
      perror("socket()");
      return -1;
    }
  // set sock reusable
  if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
		       (char *)&on, sizeof(on)) < 0)
    {
      perror("setsockopt()");
      close(sockfd);
      return -1;
    }
  if ((listenaddr = gethostbyname(HOST)) == NULL)
    {
      perror("gethostbyname()");
      close(sockfd);
      return -1;
    }
  if (ioctl(sockfd, FIONBIO, (char *)&on) < 0)
    {
      perror("ioctl()");
      close(sockfd);
      return -1;
    }
  // Prepare saddr
  bzero((char *) &saddr, sizeof(saddr));
  saddr.sin_family = AF_INET;
  saddr.sin_port = htons(PORT);
  bcopy(listenaddr->h_addr, (char*)&saddr.sin_addr, listenaddr->h_length);
  saddr.sin_addr.s_addr = INADDR_ANY;
  std::cout << "";
  if (bind(sockfd, (struct sockaddr *) &saddr, sizeof(saddr)) < 0)
    {
      perror("bind()");
      close(sockfd);
      return 1;
    }
  if (listen(sockfd, MAXCONN) < 0)
    {
      perror("listen()");
      close(sockfd);
      return 1;
    }
  socklen = sizeof(caddr);
  timeout.tv_sec = 0;
  timeout.tv_usec = 0;

  char	str[128];
  snprintf(str, 128, "Listening on %s:%d", HOST ,PORT);
  pdbg(str);
  while (1)
    {
      FD_ZERO(&fdset);
      FD_SET(sockfd, &fdset);
      // endless select
      int select_ret;
      if ((select_ret = select(sockfd + 1, &fdset, NULL, NULL, NULL)) > 0)
	{
	  newsockfd = accept4(sockfd, (struct sockaddr *) &caddr, &socklen, SOCK_NONBLOCK);
	  if (newsockfd < 0)
	    {
	      perror("accept()");
	      return -1;
	    }
	  else
	    {
	      pdbg("New client accepted !");
	      clis[select_ret].launch();
	    }
	}
      else
	{
	  perror("select()");
	  close(sockfd);
	  return 1;
	}
    }
  return 0;
}
